#include "AddUpdateDialog.h"
#include "LoadSave.h"

#include <QTimer>
#include <QMessageBox>
#include <QApplication>
#include <QDebug>

#include <DndData/TitledData.h>
#include <Xml/XmlFileNotFound.h>
#include <Xml/XmlTagNotFound.h>

/*!
\class AddUpdateDialog
\brief UI base class to manage creation and update of data.
\details Create a dialog as an instance of a subclass of this, supplying
a given specified data item and the dialog will take care of loading that
data (if it exists).
Once the dialog is displayed the user can interact with it, entering
updates into the various controls.  If the user selects the "Ok"
button the dialog will save the data from the controls into a local
TitledData object, which can be retrieved via the data() function.

Subclasses will operate on subclasses of the TitledData object.
Note that this object is only valid while the dialog exists.  If the user
rejects the dialog, the data() function returns a TitledData object
that is empty (except for its title).

Note the copying of the data, before deletion of the dialog.
 */


/*!
\brief Construct a new AddUpdateDialog
\details The new dialog is set to create or update a data item specified
by the XmlPath \a title.
\param title the specifier of the data to create or update.
\param parent QWidget to parent this dialog onto.
 */
AddUpdateDialog::AddUpdateDialog(const XmlPath &path, QWidget *parent)
    : QDialog(parent)
    , mXmlPath(path)
    , mChangesMade(false)
{
}

/*
\brief Destroy this dialog, releasing any resources.
 */
AddUpdateDialog::~AddUpdateDialog()
{
}

/*!
\fn setupData()
\brief Initialize the logic of GUI controls.
\details Override this method to setup any data in combo
boxes, build and install models and so on.  This method is
called during initialize(), before data is loaded from XML.
 */

/*!
\fn loadData()
\brief Import data from XML to initialize the UI.
\details Override this method to setup data in UI controls
using the data from the internal object returned by data().
This method is called after data is loaded successfully
from XML stored in the file-system.
 */

/*!
\brief Initialize this Dialog by setting up UI control logic.
\details This method is called when control has returned to the
Qt Event loop, after the constructor has completed.  It calls
the virtual methods setupData() to initialize control logic,
and build any models required.  Then it attempts to load the
data item specified by the xmlPath provided in the constructor.
If this is successful, the virtual loadData() method is called
to update the controls with the loaded details.  If the data
could not be loaded because the file was not found, this is
ignored - its assumed a new object is being created.  If an error
occurs during loading an error dialog is displayed.
 */
void AddUpdateDialog::initialize()
{
    qDebug() << ">>> AddUpdateDialog::initialize" << objectName();
    LoadSave *openDialog = new LoadSave(this);
    openDialog->setXmlPath(mXmlPath);
    int res = openDialog->exec();
    if (res == QDialog::Rejected)
    {
        delete openDialog;
        reject();
        return;
    }
    bool doLoad = true;
    mXmlPath = openDialog->path();
    setupData();
    try
    {
        data()->loadFromXml();
    }
    catch (XmlFileNotFound e)
    {
        // no problem, its a new item, dont load anything
        doLoad = false;
        clearData();
    }
    catch (XmlTagNotFound e)
    {
        // loaded, but an old format file was used
        // continue and load anyway
        QMessageBox::information(this, tr("Bad File Version?"),
                                 e.message());
        emit statusMessage(e.message());
    }
    catch (XmlException e)
    {
        // other problems loading the data
        QMessageBox::critical(this,
                tr("Bad data: %1").arg(data()->title()),
                e.message());
        doLoad = false;
        emit statusMessage(e.message());
    }
    if (doLoad)
        loadData();
    delete openDialog;
    qDebug() << "<<< AddUpdateDialog::initialize" << objectName();
}

/*!
  \brief Handler for the "Add Another" push button.
  \details Simply calls the initialize() method to reset the dialog and
  capture another item title for editing
 */
void AddUpdateDialog::on_addAnotherPushButton_clicked()
{
    saveXml();
    initialize();
}

/*!
  \internal
  \brief Helper method to save the data.
 */
void AddUpdateDialog::saveXml()
{
    saveData();
    try
    {
        data()->saveToXml();
        emit statusMessage(tr("Data for %1 saved to file-system").arg(data()->title()));
        emit dataUpdated();
    }
    catch (XmlException e)
    {
        QMessageBox::critical(this, tr("Could not save to XML"), e.message());
    }
}

/*!
  \brief Handler for the accepted() message
  \details Recieve the accepted() message from the buttonBox control, and
  process by saving the data from the dialogs controls to the internal
  data object by calling the saveData() method.

  An attempt is also to save the data to the file system.  If this fails a
  critical dialog is displayed.
 */
void AddUpdateDialog::on_buttonBox_accepted()
{
    saveXml();
    done(QDialog::Accepted);
}
